package com.xiaoh.dormitoryrepairreportbackend.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.xiaoh.dormitoryrepairreportbackend.config.AiConfig;
import com.xiaoh.dormitoryrepairreportbackend.model.dto.ai.AiAssignmentResult;
import com.xiaoh.dormitoryrepairreportbackend.model.dto.ai.AiRecommendationResponse;
import com.xiaoh.dormitoryrepairreportbackend.model.dto.user.UserResponse;
import com.xiaoh.dormitoryrepairreportbackend.model.entity.GeneralUser;
import com.xiaoh.dormitoryrepairreportbackend.model.entity.RepairCategory;
import com.xiaoh.dormitoryrepairreportbackend.model.entity.WorkOrder;
import com.xiaoh.dormitoryrepairreportbackend.service.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * AI工单分配服务实现类
 */
@Service
@Slf4j
public class AiWorkOrderAssignmentServiceImpl implements AiWorkOrderAssignmentService {

    @Resource
    private AiConfig aiConfig;

    @Resource
    private MaintenanceSkillService maintenanceSkillService;

    @Resource
    private GeneralUserService generalUserService;

    @Resource
    private RepairCategoryService repairCategoryService;

    @Lazy
    @Resource
    private WorkOrderService workOrderService;

    private final WebClient webClient;

    public AiWorkOrderAssignmentServiceImpl() {
        this.webClient = WebClient.builder()
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .build();
    }

    @Override
    public AiAssignmentResult assignWorkOrder(WorkOrder workOrder) {
        try {
            // 1. 获取维修类别信息
            RepairCategory category = repairCategoryService.getById(workOrder.getCategoryId());
            if (category == null) {
                return AiAssignmentResult.failure("维修类别不存在");
            }

            // 2. 获取有该技能的维修工列表
            List<Long> maintenanceIds = maintenanceSkillService.getMaintenanceIdsByCategoryId(workOrder.getCategoryId());
            if (maintenanceIds.isEmpty()) {
                return AiAssignmentResult.failure("没有找到具备相关技能的维修工");
            }

            // 3. 获取维修工详细信息
            List<GeneralUser> maintenanceUsers = generalUserService.listByIds(maintenanceIds);
            String maintenanceInfo = buildMaintenanceInfo(maintenanceUsers, category);

            // 4. 构建AI提示词
            String prompt = buildPrompt(workOrder, maintenanceInfo);

            // 5. 调用AI API
            String aiResponse = callAiApi(prompt);
            if (StrUtil.isBlank(aiResponse)) {
                return AiAssignmentResult.failure("AI服务响应为空");
            }

            // 6. 解析AI响应
            return parseAiResponse(aiResponse, maintenanceIds);

        } catch (Exception e) {
            log.error("AI分配工单失败", e);
            return AiAssignmentResult.failure("AI分配服务异常: " + e.getMessage());
        }
    }

    @Override
    public String buildPrompt(WorkOrder workOrder, String availableMaintenanceInfo) {
        return String.format(
                "你是一个宿舍维修工单分配专家。请根据以下工单信息和可用维修工信息，为工单分配最合适的维修工。\n\n" +
                        "工单信息：\n" +
                        "- 标题：%s\n" +
                        "- 描述：%s\n" +
                        "- 地址：%s\n" +
                        "- 维修类别：%s\n\n" +
                        "可用维修工信息：\n%s\n\n" +
                        "请分析工单的具体需求，考虑维修工的技能匹配度，选择最合适的维修工。\n\n" +
                        "请按以下JSON格式返回结果：\n" +
                        "{\n" +
                        "    \"recommendedMaintenanceId\": 推荐的维修工ID（数字），\n" +
                        "    \"reason\": \"推荐理由\",\n" +
                        "    \"confidence\": 置信度（0-1之间的小数）\n" +
                        "}\n\n" +
                        "注意：只返回JSON格式的结果，不要包含其他文字。",
                workOrder.getTitle(),
                workOrder.getDescription(),
                workOrder.getLocation(),
                availableMaintenanceInfo.split("\n")[0], // 取第一行作为类别名称
                availableMaintenanceInfo
        );
    }

    /**
     * 构建维修工信息字符串
     */
    private String buildMaintenanceInfo(List<GeneralUser> maintenanceUsers, RepairCategory category) {
        StringBuilder sb = new StringBuilder();
        sb.append("维修类别：").append(category.getCategoryName()).append("\n");
        sb.append("可用维修工：\n");

        for (GeneralUser user : maintenanceUsers) {
            sb.append("- ID: ").append(user.getId())
                    .append(", 姓名: ").append(user.getNickName())
                    .append(", 联系方式: ").append(user.getPhoneNumber())
                    .append("\n");
        }

        return sb.toString();
    }

    /**
     * 调用AI API
     */
    public String callAiApi(String prompt) {
        log.info("调用AI API，提示词：{}，\nconfig：{}", prompt, aiConfig);
        try {
            // 构建请求体
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("model", aiConfig.getModel());

            List<Map<String, String>> messages = new ArrayList<>();
            Map<String, String> message = new HashMap<>();
            message.put("role", "user");
            message.put("content", prompt);
            messages.add(message);
            requestBody.put("messages", messages);

            requestBody.put("temperature", 0.3);

            // 发送请求
            Mono<String> responseMono = webClient.post()
                    .uri(aiConfig.getBaseUrl())
                    .header("Authorization", "Bearer " + aiConfig.getApiKey())
                    .header("Content-Type", "application/json")
                    .bodyValue(requestBody)
                    .retrieve()
                    .bodyToMono(String.class)
                    .timeout(Duration.ofSeconds(aiConfig.getTimeout()));

            String response = responseMono.block();
            log.info("AI API响应: {}", response);

            // 解析响应获取content
            JSONObject responseJson = JSONUtil.parseObj(response);
            if (responseJson.containsKey("choices")) {
                return responseJson.getJSONArray("choices")
                        .getJSONObject(0)
                        .getJSONObject("message")
                        .getStr("content");
            }
        } catch (Exception e) {
            log.error("调用AI API失败", e);
        }
        return null;
    }

    /**
     * 解析AI响应
     */
    private AiAssignmentResult parseAiResponse(String aiResponse, List<Long> availableMaintenanceIds) {
        try {
            // 提取JSON部分
            String jsonStr = extractJson(aiResponse);
            if (StrUtil.isBlank(jsonStr)) {
                return AiAssignmentResult.failure("AI响应格式不正确");
            }

            JSONObject json = JSONUtil.parseObj(jsonStr);
            Long recommendedId = json.getLong("recommendedMaintenanceId");
            String reason = json.getStr("reason");
            Double confidence = json.getDouble("confidence");

            // 验证推荐的维修工ID是否在可用列表中
            if (recommendedId == null || !availableMaintenanceIds.contains(recommendedId)) {
                return AiAssignmentResult.failure("AI推荐的维修工ID无效");
            }

            return AiAssignmentResult.success(recommendedId, availableMaintenanceIds, reason, confidence);

        } catch (Exception e) {
            log.error("解析AI响应失败: {}", aiResponse, e);
            return AiAssignmentResult.failure("解析AI响应失败: " + e.getMessage());
        }
    }

    /**
     * 从文本中提取JSON
     * 处理GLM-Z1格式：<think>推理内容</think>实际输出内容
     */
    private String extractJson(String text) {
        if (StrUtil.isBlank(text)) {
            return "";
        }

        log.debug("原始AI响应: {}", text);

        // 处理GLM-Z1格式：移除<think></think>标签及其内容
        String cleanedText = text;
        if (text.contains("<think>") && text.contains("</think>")) {
            // 找到</think>标签的位置，提取之后的内容
            int endThinkIndex = text.indexOf("</think>");
            if (endThinkIndex != -1) {
                cleanedText = text.substring(endThinkIndex + "</think>".length()).trim();
                log.debug("移除<think>标签后的内容: {}", cleanedText);
            }
        }

        // 尝试提取JSON对象（支持嵌套）
        String jsonStr = extractJsonObject(cleanedText);
        if (StrUtil.isNotBlank(jsonStr)) {
            log.debug("提取到的JSON: {}", jsonStr);
            return jsonStr;
        }

        log.warn("未能从AI响应中提取到有效JSON，返回清理后的文本: {}", cleanedText);
        // 如果没有找到JSON，返回清理后的文本
        return cleanedText.trim();
    }

    /**
     * 从文本中提取JSON对象（支持嵌套）
     */
    private String extractJsonObject(String text) {
        if (StrUtil.isBlank(text)) {
            return "";
        }

        int firstBrace = text.indexOf('{');
        if (firstBrace == -1) {
            return "";
        }

        int braceCount = 0;
        int start = firstBrace;

        for (int i = firstBrace; i < text.length(); i++) {
            char c = text.charAt(i);
            if (c == '{') {
                braceCount++;
            } else if (c == '}') {
                braceCount--;
                if (braceCount == 0) {
                    // 找到完整的JSON对象
                    return text.substring(start, i + 1);
                }
            }
        }

        return "";
    }

    @Override
    public List<UserResponse> recommendMaintenanceWorkers(Long workOrderId, Integer count) {
        try {
            // 1. 获取工单信息
            WorkOrder workOrder = workOrderService.getById(workOrderId);
            if (workOrder == null) {
                log.warn("工单不存在: {}", workOrderId);
                return new ArrayList<>();
            }

            // 2. 获取维修类别信息
            RepairCategory category = repairCategoryService.getById(workOrder.getCategoryId());
            if (category == null) {
                log.warn("维修类别不存在: {}", workOrder.getCategoryId());
                return new ArrayList<>();
            }

            // 3. 获取有该技能的维修工列表
            List<Long> maintenanceIds = maintenanceSkillService.getMaintenanceIdsByCategoryId(workOrder.getCategoryId());
            if (maintenanceIds.isEmpty()) {
                log.warn("没有找到具备相关技能的维修工");
                return new ArrayList<>();
            }

            // 4. 获取维修工详细信息
            List<GeneralUser> maintenanceUsers = generalUserService.listByIds(maintenanceIds);
            String maintenanceInfo = buildMaintenanceInfo(maintenanceUsers, category);

            // 5. 构建AI推荐提示词
            String prompt = buildRecommendationPrompt(workOrder, maintenanceInfo, count != null ? count : 5);

            // 6. 调用AI API
            String aiResponse = callAiApi(prompt);
            if (StrUtil.isBlank(aiResponse)) {
                log.warn("AI服务响应为空");
                return convertToUserResponseList(maintenanceUsers.subList(0, Math.min(count != null ? count : 5, maintenanceUsers.size())));
            }

            // 7. 解析AI推荐结果
            List<Long> recommendedIds = parseRecommendationResponse(aiResponse, maintenanceIds);

            // 8. 转换为UserResponse
            List<GeneralUser> recommendedUsers = generalUserService.listByIds(recommendedIds);
            return convertToUserResponseList(recommendedUsers);

        } catch (Exception e) {
            log.error("AI推荐维修人员失败", e);
            // 降级处理：返回前几个有技能的维修工
            try {
                WorkOrder fallbackWorkOrder = workOrderService.getById(workOrderId);
                if (fallbackWorkOrder != null) {
                    List<Long> maintenanceIds = maintenanceSkillService.getMaintenanceIdsByCategoryId(fallbackWorkOrder.getCategoryId());
                    if (!maintenanceIds.isEmpty()) {
                        List<GeneralUser> fallbackUsers = generalUserService.listByIds(
                                maintenanceIds.subList(0, Math.min(count != null ? count : 5, maintenanceIds.size())));
                        return convertToUserResponseList(fallbackUsers);
                    }
                }
            } catch (Exception fallbackException) {
                log.error("降级处理也失败", fallbackException);
            }
            return new ArrayList<>();
        }
    }

    /**
     * 构建AI推荐提示词
     */
    private String buildRecommendationPrompt(WorkOrder workOrder, String availableMaintenanceInfo, int count) {
        return String.format(
                "你是一个宿舍维修工单分配专家。请根据以下工单信息和可用维修工信息，推荐%d个最合适的维修工。\n\n" +
                        "工单信息：\n" +
                        "- 标题：%s\n" +
                        "- 描述：%s\n" +
                        "- 地址：%s\n" +
                        "- 维修类别：%s\n\n" +
                        "可用维修工信息：\n%s\n\n" +
                        "请分析工单的具体需求，考虑维修工的技能匹配度，按优先级推荐%d个维修工。\n\n" +
                        "请按以下JSON格式返回结果：\n" +
                        "{\n" +
                        "    \"recommendations\": [\n" +
                        "        {\n" +
                        "            \"maintenanceId\": 维修工ID（数字），\n" +
                        "            \"reason\": \"推荐理由\",\n" +
                        "            \"priority\": 优先级（1-5，1最高）\n" +
                        "        }\n" +
                        "    ]\n" +
                        "}\n\n" +
                        "注意：只返回JSON格式的结果，不要包含其他文字。",
                count,
                workOrder.getTitle(),
                workOrder.getDescription(),
                workOrder.getLocation(),
                availableMaintenanceInfo.split("\n")[0], // 取第一行作为类别名称
                availableMaintenanceInfo,
                count
        );
    }

    /**
     * 解析AI推荐响应
     */
    private List<Long> parseRecommendationResponse(String aiResponse, List<Long> availableMaintenanceIds) {
        try {
            String jsonStr = extractJson(aiResponse);
            if (StrUtil.isBlank(jsonStr)) {
                return availableMaintenanceIds.subList(0, Math.min(5, availableMaintenanceIds.size()));
            }

            JSONObject json = JSONUtil.parseObj(jsonStr);
            if (!json.containsKey("recommendations")) {
                return availableMaintenanceIds.subList(0, Math.min(5, availableMaintenanceIds.size()));
            }

            List<Long> recommendedIds = new ArrayList<>();
            json.getJSONArray("recommendations").forEach(item -> {
                JSONObject recommendation = (JSONObject) item;
                Long maintenanceId = recommendation.getLong("maintenanceId");
                if (maintenanceId != null && availableMaintenanceIds.contains(maintenanceId)) {
                    recommendedIds.add(maintenanceId);
                }
            });

            return recommendedIds.isEmpty() ?
                    availableMaintenanceIds.subList(0, Math.min(5, availableMaintenanceIds.size())) :
                    recommendedIds;

        } catch (Exception e) {
            log.error("解析AI推荐响应失败", e);
            return availableMaintenanceIds.subList(0, Math.min(5, availableMaintenanceIds.size()));
        }
    }

    /**
     * 转换为UserResponse列表
     */
    private List<UserResponse> convertToUserResponseList(List<GeneralUser> users) {
        return users.stream().map(user -> {
            UserResponse response = new UserResponse();
            response.setId(user.getId());
            response.setAccountName(user.getAccountName());
            response.setNickName(user.getNickName());
            response.setEmail(user.getEmail());
            response.setPhoneNumber(user.getPhoneNumber());
            response.setUserType(user.getUserType());
            response.setCreatedAt(user.getCreatedAt());
            response.setUpdatedAt(user.getUpdatedAt());
            return response;
        }).collect(Collectors.toList());
    }

    @Override
    public AiRecommendationResponse recommendMaintenanceWorkersWithAiResult(Long workOrderId, Integer count) {
        try {
            // 1. 获取工单信息
            WorkOrder workOrder = workOrderService.getById(workOrderId);
            if (workOrder == null) {
                log.warn("工单不存在: {}", workOrderId);
                return AiRecommendationResponse.failure("工单不存在", new ArrayList<>());
            }

            // 2. 使用与添加工单时一致的AI分配逻辑
            AiAssignmentResult aiResult = assignWorkOrder(workOrder);

            // 3. 获取推荐的维修工信息
            List<UserResponse> recommendedWorkers = new ArrayList<>();

            if (aiResult.isSuccess()) {
                // AI分配成功，获取推荐的维修工和候选维修工信息
                List<Long> workerIds = new ArrayList<>();

                // 添加推荐的维修工
                if (aiResult.getRecommendedMaintenanceId() != null) {
                    workerIds.add(aiResult.getRecommendedMaintenanceId());
                }

                // 添加其他候选维修工，直到达到请求的数量
                if (aiResult.getCandidateMaintenanceIds() != null) {
                    int remainingCount = (count != null ? count : 5) - workerIds.size();
                    aiResult.getCandidateMaintenanceIds().stream()
                            .filter(id -> !workerIds.contains(id))
                            .limit(remainingCount)
                            .forEach(workerIds::add);
                }

                // 获取维修工详细信息
                if (!workerIds.isEmpty()) {
                    List<GeneralUser> workers = generalUserService.listByIds(workerIds);
                    recommendedWorkers = convertToUserResponseList(workers);
                }
            } else {
                // AI分配失败，降级处理：返回有技能的维修工
                try {
                    List<Long> maintenanceIds = maintenanceSkillService.getMaintenanceIdsByCategoryId(workOrder.getCategoryId());
                    if (!maintenanceIds.isEmpty()) {
                        int limitCount = Math.min(count != null ? count : 5, maintenanceIds.size());
                        List<GeneralUser> fallbackUsers = generalUserService.listByIds(
                                maintenanceIds.subList(0, limitCount));
                        recommendedWorkers = convertToUserResponseList(fallbackUsers);
                    }
                } catch (Exception fallbackException) {
                    log.error("降级处理失败", fallbackException);
                }
            }

            return AiRecommendationResponse.success(aiResult, recommendedWorkers);

        } catch (Exception e) {
            log.error("AI推荐维修人员失败", e);
            // 降级处理：返回前几个有技能的维修工
            try {
                WorkOrder fallbackWorkOrder = workOrderService.getById(workOrderId);
                if (fallbackWorkOrder != null) {
                    List<Long> maintenanceIds = maintenanceSkillService.getMaintenanceIdsByCategoryId(fallbackWorkOrder.getCategoryId());
                    if (!maintenanceIds.isEmpty()) {
                        int limitCount = Math.min(count != null ? count : 5, maintenanceIds.size());
                        List<GeneralUser> fallbackUsers = generalUserService.listByIds(
                                maintenanceIds.subList(0, limitCount));
                        List<UserResponse> fallbackWorkers = convertToUserResponseList(fallbackUsers);
                        return AiRecommendationResponse.failure("AI推荐服务异常: " + e.getMessage(), fallbackWorkers);
                    }
                }
            } catch (Exception fallbackException) {
                log.error("降级处理也失败", fallbackException);
            }
            return AiRecommendationResponse.failure("AI推荐服务异常: " + e.getMessage(), new ArrayList<>());
        }
    }
}
